home *** CD-ROM | disk | FTP | other *** search
/ By Popular Request 2.0 / By Popular Request 2.0 (Arsenal Computer).ISO / amiga_1 / amnfrm55.lha / Inform / examples / toyshop.inf < prev   
Text File  |  1995-08-02  |  39KB  |  1,012 lines

  1. ! ----------------------------------------------------------------------------
  2. !  Toyshop:  An Inform Demonstration                       Version 2, 19/8/94
  3. !
  4. !  This is not a real game.  The main example for Inform 5 is "Advent",
  5. !  a port of Colossal Cave.  Since that's something of an antique, and most
  6. !  of the objects in it are rather simple, this is a collection of more
  7. !  exotic features and peculiar objects.  Note that "Advent" has plenty of
  8. !  interesting doors and also provides a good lantern and bottled water.
  9. !
  10. !  To win, simply find 5 interesting things to do and leave by the main exit!
  11. !
  12. !       Object            An example of...
  13. !
  14. !  >SA  satchel           Container into which the game silently puts things
  15. !  >HE  helium balloon    Something moving under the control of a daemon
  16. !  >CA  little red car    Vehicle, and pushable from place to place
  17. !  >PF  padded floor      Scenery present in several rooms at once
  18. !  >GR  hand grenade      Timed events: a grenade and its pin
  19. !  >MA  matchbook         Simple fire and matches; changing inventory styles
  20. !  >WC  white candles     A stock of objects identical to each other
  21. !  >GL  white gloves      Two independent objects which can behave as a pair
  22. !  >CO  green cone        Easy before and after rules
  23. !  >HW  high window       Starting and stopping daemons
  24. !  >BC  bolted cupboard   A typical locked container (with key)
  25. !  >GB  glass box         Container light can get through
  26. !  >SB  steel box         Container light can't get through
  27. !  >CU  building cubes    A complicated class definition; piles of objects
  28. !  >CH  Christopher       Someone you can talk to, and persuade to do things
  29. !  >OF  Office            Rules about moving in a particular direction
  30. !  >TB  toothed bag       A container with ideas about what it will allow
  31. !  >SL  spirit level      Something to put on top of things
  32. !  >BB  blackboard        A blackboard to write messages on
  33. !
  34. !  (The code is marked with >SA and so on for easy access with a text editor)
  35. ! ----------------------------------------------------------------------------
  36.  
  37. Switches dv5;
  38.  
  39. !   First, the banner:
  40.  
  41. Constant Story "TOYSHOP";
  42. Constant Headline "^An Interactive Demonstration^\
  43.              Copyright (c) 1994 by Graham Nelson. All rights given away.^";
  44.  
  45. !   The blackboard code won't compile under Inform 5.2 (because I5.2
  46. !   misunderstood '"'); if you're using 5.2, comment out the next line:
  47.  
  48. Constant WITH_BOARD;
  49.  
  50. !   Now we serve notice to Inform that we do not wish to use the standard
  51. !   routine for the Burn action, and will instead be defining our own:
  52.  
  53. Replace BurnSub;
  54.  
  55. !   And include the first of the three standard library files:
  56.  
  57. Include "Parser";
  58.  
  59. ! ----------------------------------------------------------------------------
  60. ! >SA  Ungenerously, the player can only carry at most 4 things, but there's
  61. !      a satchel to carry other things around in...
  62. ! ----------------------------------------------------------------------------
  63.  
  64. Object satchel "satchel"
  65.   with description "Big and with a smile painted on it.",
  66.        name "satchel", article "your",
  67.        when_closed "Your satchel lies on the floor.",
  68.        when_open "Your satchel lies open on the floor.",
  69.   has  container open openable;
  70.  
  71. Constant MAX_OBJECTS 4;
  72. Constant SACK_OBJECT satchel;
  73.  
  74. !   We're going to use the full, most elaborate scoring system the
  75. !   library provides, so we define all this...
  76.  
  77. Constant TASKS_PROVIDED;
  78. Constant NUMBER_TASKS 5;
  79. Global   task_scores  initial 1 1 1 1 1;
  80. Constant MAX_SCORE 5;
  81.  
  82. !   Finally, include the library of standard verbs and actions...
  83.  
  84. Include "VerbLib";
  85.  
  86.  
  87. ! ----------------------------------------------------------------------------
  88. !   Off we go into the Toyshop...
  89. ! ----------------------------------------------------------------------------
  90.  
  91. Object Toyshop "Toyshop"
  92.   with description
  93.           "The centre of a long east-west hall.  Shelves are lined \
  94.            with toys, painted clowns face you from the walls and \
  95.            the floor is lightly padded with colourful mats.  A doorway \
  96.            leads north, with a red warning triangle above it.",
  97.        name "clowns" "painted" "shelves" "triangle",
  98.        e_to East_End, w_to West_End, n_to Danger_Zone
  99.   has  light;
  100.  
  101. ! ----------------------------------------------------------------------------
  102. ! >HE  The balloon is completely self-contained as a piece of code, except
  103. !      that it does not set itself going (though this could have been
  104. !      arranged): it is set going in the Initialise() routine.
  105. !
  106. !   Notice that the "after" for Drop takes away the "moved" attribute.
  107. !   This is a device to ensure that the "initial" message will always be
  108. !   the one displayed.  (There are other ways of doing this, too.)
  109. ! ----------------------------------------------------------------------------
  110.  
  111. Nearby balloon "helium balloon"
  112.   with description "Blue, with a yellow smile.",
  113.        name "helium" "balloon" "blue" "string",
  114.        initial "A balloon nestles on the ceiling, its long string hanging.",
  115.        before
  116.        [; Attack: remove self; StopDaemon(self);
  117.                 "Easily, you burst the balloon.  Pop!^^\
  118.                  Shame it was irreplaceable, really.";
  119.        ],
  120.        after
  121.        [; Take: "You take the balloon by its string.  It's buoyant!";
  122.           Drop: give balloon ~moved;
  123.                 "The balloon rises gracefully to the ceiling.";
  124.        ],
  125.        time_left 0,
  126.        daemon
  127.        [ from_room to_room; if (random(3)~=1) rfalse;
  128.           from_room=parent(self);
  129.           if (from_room==East_End or West_End) to_room=Toyshop;
  130.           if (from_room==Toyshop)
  131.           {   if (random(2)==1) to_room=East_End;
  132.               else to_room=West_End;
  133.           }
  134.           if (to_room==0) rfalse;
  135.           move self to to_room;
  136.           if (location==from_room)
  137.               print_ret "^A breeze blows the balloon away to the ",
  138.                         object to_room, ".";
  139.           if (location==to_room)
  140.               print_ret "^A breeze blows the balloon in from the ",
  141.                         object from_room, ".";
  142.        ],
  143.   has  light;    ! Dismal, dismal pun
  144.  
  145. ! ----------------------------------------------------------------------------
  146. ! >CA  There are two exceptions to the ordinary before/after rules, for
  147. !      vehicles and things which can be pushed from place to place: this car
  148. !      demonstrates both at once.
  149. !
  150. !   The "before" for PushDir (push in a named direction) must call
  151. !   AllowPushDir and then return true to signify that the push is legal.
  152. !
  153. !   The "before" for Go must return true to signify that travelling in
  154. !   the object is legal.  (Note that it must also be enterable.)
  155. ! ----------------------------------------------------------------------------
  156.  
  157. Nearby car "little red car"
  158.   with name "little" "red" "car" "kar1",
  159.        description "Large enough to sit inside.  Among the controls is a \
  160.                  prominent on/off switch.  The numberplate is KAR 1.",
  161.        when_on  "The red car sits here, its engine still running.",
  162.        when_off "A little red car is parked here.",
  163.        before
  164.        [; PushDir: AllowPushDir(); rtrue;
  165.           Go: if (car has on) { Achieved(1); "Brmm!  Brmm!"; }
  166.               print "(The ignition is off at the moment.)^";
  167.        ],
  168.        after
  169.        [; PushDir: "The car rolls very slowly as you push it.";
  170.        ],
  171.   has  switchable enterable static container open;
  172.  
  173. Object small_note "small note" car
  174.   with name "small" "note",
  175.        description
  176.            "  !!!! FROBOZZ MAGIC CAR COMPANY !!!!^\
  177.            ^Hello, Driver!^\
  178.            ^Instructions for use:^\
  179.            ^Switch on the ignition and off you go!^\
  180.            ^Warranty:^\
  181.            ^This car is guaranteed against all defects for a period of \
  182.             76 milliseconds from date of purchase or until used, \
  183.             whichever comes first.^\
  184.            ^Good Luck!";
  185.  
  186. ! ----------------------------------------------------------------------------
  187. ! >PF  An example of an object spread across several (three) rooms:
  188. ! ----------------------------------------------------------------------------
  189.  
  190. Object padded_floor "padded floor"
  191.   with name "padded" "floor" "mats" "padding",
  192.        description "To protect little children and adventurers.",
  193.        before
  194.        [; Take: "It is protected from little children and adventurers.";
  195.        ],
  196.        found_in East_End Toyshop West_End
  197.   has  scenery;
  198.  
  199. ! ----------------------------------------------------------------------------
  200.  
  201. Object Danger_Zone "Danger Zone"
  202.   with description
  203.           "This is the Danger Zone, which you should know better \
  204.            than to go into.  A single door leads back south.",
  205.        s_to Toyshop
  206.   has  light;
  207.  
  208. ! ----------------------------------------------------------------------------
  209. ! >GR  A classic example of a timer (or, as some people call them and
  210. !      appropriately so in this case, a fuse).  To demonstrate stopping
  211. !      a timer before the alarm (and for fun), there is also a pin:
  212. ! ----------------------------------------------------------------------------
  213.  
  214. Nearby grenade "nasty-looking hand grenade"
  215.   with name "hand" "grenade" "nasty" "nasty-looking",
  216.        initial "A nasty-looking hand grenade (there is no other kind) \
  217.                 rolls about irresponsibly on the floor.",
  218.        description "Not recommended for children under 90.",
  219.        before
  220.        [; Pull: if (self has general) "Too late for that.";
  221.               StartTimer(self, 5); give self general;
  222.               move the_pin to player;
  223.               "You pull the pin out, an irrevocable act.";
  224.        ],
  225.        time_left 0,
  226.        time_out
  227.        [;  deadflag=1;
  228.            "^An immense explosion suddenly demolishes the toyshop!^^\
  229.              Will you never learn?";
  230.        ],
  231.   has  transparent;
  232.  
  233. Object the_pin "pin" grenade
  234.   with name "pin",
  235.        description "The pin is designed to be easy to pull.",
  236.        before
  237.        [; Take, Pull: if (self in grenade) <<Pull grenade>>;
  238.           Insert:
  239.               if (self notin grenade && second==grenade)
  240.               {   StopTimer(grenade); move self to grenade;
  241.                   give grenade ~general;
  242.                   "Amazing!  You got the pin back into the grenade!";
  243.               }
  244.        ];
  245.  
  246. ! ----------------------------------------------------------------------------
  247. ! >MA  This is a matchbook of five matches, which is quite simple in that you
  248. !      can only actually have one match at a time: otherwise, it's quite
  249. !      a full implementation.  Note that the inventory lines for the match
  250. !      and the matchbook are coded here.  Note also that the "match" object
  251. !      returns to the book even when the book is empty, so that the parser
  252. !      will still understand requests for matches - which the "before" rule,
  253. !      which automatically removes matches when needed, can then turn down.
  254. !
  255. !      The matchbook has a daemon whose job is to tidy up lost matches.  One
  256. !      might expect this rule to be coded with an "after" routine, to trap
  257. !      the player dropping matches.  But suppose there were a magpie in the
  258. !      game, and it flew down and stole the match but left the matchbook!
  259. !      As it happens there isn't, but this is better form.
  260. ! ----------------------------------------------------------------------------
  261.  
  262. Object matchbook "matchbook" Danger_Zone
  263.   with name "matchbook" "book" "matches",
  264.        number 5,
  265.        before
  266.        [; Burn: if (match has light)
  267.                 {   remove match; remove matchbook;
  268.                     "What a waste of matches!";
  269.                 }
  270.        ],
  271.        invent
  272.        [ i; if (inventory_stage==2)
  273.             {   i=self.number;
  274.                 if (i==0) print " (empty)";
  275.                 if (i==1) print " (1 match left)";
  276.                 if (i>1)  print " (",i," matches left)";
  277.             }
  278.        ],
  279.        description
  280.        [ i; print "The cover advertisement reads \
  281.                   ~Curses - Adventure of a Lunchtime~.  The book ";
  282.             i=self.number;
  283.             if (i==0) "is empty.";
  284.             if (i==1) "has a single match left.";
  285.             print "contains ", i, " matches.^";
  286.        ],
  287.        time_left 0,
  288.        daemon
  289.        [;   if (match notin matchbook && match notin player)
  290.             {   move match to matchbook;
  291.                 if (match has light)
  292.                 {   give match ~light; StopTimer(match); }
  293.                 StopDaemon(self);
  294.             }
  295.        ],
  296.   has  transparent;
  297.  
  298. Object match "match" matchbook
  299.   with parse_name
  300.        [ i j;   if (self has light) j='burning'; else j='unlit';
  301.                 while (NextWord()=='match' or j) i++;
  302.                 return i;
  303.        ],
  304.        time_left 0, article "an",
  305.        before
  306.        [ i; if (self in matchbook)
  307.             {   i=matchbook.number;
  308.                 if (i==0) "There are no matches left in the book.";
  309.                 i--; matchbook.number=i;
  310.                 move self to player; StartDaemon(matchbook);
  311.                 print "(taking a match from the book, which ";
  312.                 if (i==0) print "is now empty)^";
  313.                 if (i==1) print "has one more left)^";
  314.                 if (i>1)  print "has ", i, " left)^";
  315.                 self.article = "an";
  316.             }
  317.             Take, Remove: if (self in player) "Done.";
  318.             Burn:
  319.                 if (self has light) "The match is already alight.";
  320.                 if (matchbook notin player)
  321.                    "You need the matchbook to strike the match.";
  322.                 give self light; StartTimer(self, 2+random(3));
  323.                 self.article = "a";
  324.                 "You strike the match.";
  325.        ],
  326.        short_name
  327.        [;   if (self has light) print "burning match";
  328.                            else print "unlit match";
  329.             rtrue;
  330.        ],
  331.        time_out
  332.        [;   move self to matchbook; give self ~light;
  333.             "You drop the match as the flame reaches your finger.";
  334.        ];
  335.  
  336. ! ----------------------------------------------------------------------------
  337. ! >WC  And now, a proper solution to the "matchbook problem": a box of candles
  338. !      where you really can take as many as you like!
  339. !      (Exercise: make the candles lightable.  You'll find the game then
  340. !      divides candles into lit and unlit ones automatically.)
  341. !
  342. !      Actually, there is a more sophisticated way of defining such objects.
  343. !      This is almost perfect, except that "take candles" will not pick up
  344. !      all the candles in sight (though "take four candles", etc., will work).
  345. !      For the deluxe way to code this, see the "Balances" example game.
  346. ! ----------------------------------------------------------------------------
  347.  
  348. Class  candle_class
  349.   with name "wax" "candle" "candles",
  350.        short_name "wax candle", plural "wax candles",
  351.        description "It looks just like all the other candles.",
  352.        before
  353.        [; Burn: "Disappointingly, the wick refuses to burn."; ];
  354.  
  355. Object candle_box "grey tin box" Danger_Zone
  356.   with name "tin" "box" "grey",
  357.        description
  358.            "A grey tin box of ~Major's Candles~.",
  359.   has  container openable;
  360. Nearby c1 "c" class candle_class;
  361. Nearby c2 "c" class candle_class;
  362. Nearby c3 "c" class candle_class;
  363. Nearby c4 "c" class candle_class;
  364. Nearby c5 "c" class candle_class;
  365. Nearby c6 "c" class candle_class;
  366. Nearby c7 "c" class candle_class;
  367. Nearby c8 "c" class candle_class;
  368.  
  369. ! ----------------------------------------------------------------------------
  370.  
  371. Object East_End "East End"
  372.   with name "dolls" "nurses",
  373.        description
  374.           "The eastern end of the toyshop is pink, and dolls and \
  375.            nurses line the shelves right up to the high window.  \
  376.            A dark doorway leads to a northern side chamber.",
  377.        w_to Toyshop, n_to DarkRoom
  378.   has  light;
  379.  
  380.  
  381. ! ----------------------------------------------------------------------------
  382. ! >GL  The following example, suggested to the author by Richard Tucker,
  383. !      demonstrates an apparently tricky case of objects with associated
  384. !   sub-objects.  The pair of white gloves behaves just like any other item
  385. !   of clothing - but the player can also use the left and right gloves
  386. !   independently, can take away or wear only one and so on.  When they
  387. !   come back together (even in a cupboard, say, or on a mantelpiece)
  388. !   they are called a pair again.
  389. !
  390. !   We can do this with only three objects, one daemon and one rule.
  391. !   
  392. !   When the gloves are together, and the player refers to an individual
  393. !   glove, the before rule splits up the pair and starts the daemon.
  394. !   Once active, the daemon tries every turn to re-join them into a pair.
  395. !   (If it succeeds, it turns itself off.)
  396. !
  397. !   Note that the "pair of gloves" object has the "general" flag exactly when
  398. !   the gloves are apart.  When they are together, it contains the individual
  399. !   glove objects, and is flagged as "transparent" so that the parser knows
  400. !   the player can see and refer to them.
  401. ! ----------------------------------------------------------------------------
  402.  
  403. Nearby gloves "white gloves"
  404.   with article "a pair of",
  405.        name "white" "gloves" "pair" "of",
  406.        time_left 0,
  407.        daemon
  408.        [;  if (parent(right_glove)~=parent(left_glove)) rfalse;
  409.            if ((left_glove has worn && right_glove hasnt worn)
  410.                || (left_glove hasnt worn && right_glove has worn)) rfalse;
  411.            if (left_glove has worn) give gloves worn; else give gloves ~worn;
  412.            move gloves to parent(right_glove); give gloves ~general;
  413.  
  414.            move right_glove to gloves; move left_glove to gloves;
  415.            give right_glove ~worn;    give left_glove ~worn;
  416.            
  417.            StopDaemon(self);
  418.        ],
  419.   has  clothing transparent;
  420.  
  421. Class  glove_class
  422.   with article "the",
  423.        name "white" "glove",
  424.        before
  425.        [;  if (self notin gloves) rfalse;
  426.            move left_glove to parent(gloves); move right_glove to parent(gloves);
  427.            if (gloves has worn)
  428.            {   give left_glove worn; give right_glove worn;
  429.            }
  430.            give gloves general; remove gloves;
  431.            StartDaemon(gloves);
  432.        ],
  433.   has  clothing;
  434. Object left_glove "left glove" gloves
  435.  class glove_class
  436.   with description "White silk, monogrammed with a scarlet R.",
  437.        name "left";
  438. Object right_glove "right glove" gloves
  439.  class glove_class,
  440.   with description "White silk, monogrammed with a scarlet T.",
  441.        name "right";
  442.  
  443. ! ----------------------------------------------------------------------------
  444. !   ...and that's all: the "gloves" code is self-contained.
  445. !
  446. !   Exercise for the reader: hide a (sharp) jewel inside the left glove.
  447. !     (Alter the glove class to make them containers open only when not worn.
  448. !      Add two "after" rules to warn the player if there's something sharp
  449. !      to the touch, one for putting on the pair of gloves, one for putting on
  450. !      an individual glove.)
  451. ! ----------------------------------------------------------------------------
  452.  
  453.  
  454. ! ----------------------------------------------------------------------------
  455. ! >CO  An example from the manual... but which actually solves a puzzle here:
  456. ! ----------------------------------------------------------------------------
  457.  
  458. Object cone "green cone" East_End
  459.   with name "green" "cone" "emerald" "marzipan",
  460.        describe
  461.        [; if (cone has moved)
  462.               "^A misshapen cone of green marzipan sits here.";
  463.           "^Nearby is an emerald green cone, one foot high.";
  464.        ],
  465.        description "The cone seems to be made of emerald-coloured \
  466.                     marzipan.",
  467.        before
  468.        [; Eat: if (random(100) <= 30)
  469.                {   deadflag = 1;
  470.                    "Unfortunately, you seem to be allergic to almonds.";
  471.                }
  472.                "You nibble at a corner of the cone.";
  473.        ],
  474.        after
  475.        [; Take: "Taken.  (Your hands are smeared with marzipan.)";
  476.           Drop: cone.description = "The cone is a vague green mess.";
  477.                 "The cone drops to the floor and sags a little.";
  478.        ],
  479.   has  edible;
  480.  
  481. ! ----------------------------------------------------------------------------
  482. ! >HW  It's the draught from this slightly-concealed window which propels the
  483. !      balloon:
  484. ! ----------------------------------------------------------------------------
  485.  
  486. Object high_window "high window" East_End
  487.   with name "high" "window",
  488.        description
  489.        [;  print "A narrow, high window ";
  490.            if (self has open) "through which a draught blows.";
  491.            "which is closed.";
  492.        ],
  493.        after
  494.        [; Open: StartDaemon(balloon);
  495.           Close: Achieved(2); StopDaemon(balloon);
  496.        ],
  497.   has  scenery openable open;
  498.  
  499. ! ----------------------------------------------------------------------------
  500. ! >BC  A typical locked container, containing a rather pathetic prize...
  501. ! ----------------------------------------------------------------------------
  502.  
  503. Object cupboard "bolted cupboard" East_End
  504.   with name "bolted" "cupboard",
  505.        describe
  506.        [; if (self hasnt open) "^A shut cupboard is bolted to one wall.";
  507.           "^Bolted up on one wall is an open cupboard.";
  508.        ],
  509.        with_key key
  510.   has  locked container openable lockable static;
  511.  
  512. Object boiled_sweet "boiled sweet" cupboard
  513.   with name "boiled" "sweet",
  514.        after
  515.        [; Eat: Achieved(0);
  516.                "It takes an irritatingly long time to eat.";
  517.        ],
  518.   has  edible;
  519.  
  520. ! ----------------------------------------------------------------------------
  521. ! >GB  This is really to demonstrate "transparent".  Shutting up the glowing
  522. ! >SB  ball in the glass box does not make the room go dark: shutting it up
  523. !      in the steel box does.  Also, you can examine things in the glass box
  524. !   even when the glass box is shut.
  525. ! ----------------------------------------------------------------------------
  526.  
  527. Object DarkRoom "Dark Room"
  528.   with description "A featureless storage room, hardly worth illumination.",
  529.        cant_go "The only exit is back south.",
  530.        s_to East_End;
  531.  
  532. Nearby glass_box "glass box with a lid"
  533.   with name "glass" "box" "with" "lid"
  534.   has  container transparent openable open;
  535.  
  536. Nearby steel_box "steel box with a lid"
  537.   with name "steel" "box" "with" "lid"
  538.   has  container openable open;
  539.  
  540.  
  541. Object West_End "West End"
  542.   with name "soldiers" "model" "aircraft" "planes",
  543.        description
  544.           "The western end of the toyshop is blue, and soldiers and \
  545.            model aircraft line the shelves.  A small office lies to \
  546.            the south.",
  547.        e_to Toyshop, s_to Office
  548.   has  light;
  549.  
  550. ! ----------------------------------------------------------------------------
  551. ! >CU  An interesting class definition.  Imagine trying to code this up
  552. !      without classes...  (The following is not for the fainthearted.)
  553. !
  554. !   Note that with the "describe" routine missing, the game would still
  555. !   correctly describe stacks of cubes: just a little less elegantly.
  556. ! ----------------------------------------------------------------------------
  557.  
  558. Attribute is_cube;
  559.  
  560. Class  Cube_Class
  561.   with description "Just a child's building block, four inches on a side.",
  562.        parse_name
  563.        [ i j;
  564.          for (::)
  565.          {   j=NextWord();
  566.              if (j=='block' or 'cube' or 'building' || j==self.name) i++;
  567.              else
  568.              {   if (j=='blocks' or 'cubes')
  569.                  {   parser_action=##PluralFound; i++; }
  570.                  else return i;
  571.              }
  572.          }
  573.        ],
  574.        describe
  575.        [ c d e;
  576.            d=child(self);
  577.            while (d~=0 && d has is_cube)
  578.            {   c++; e=d; d=child(d); }
  579.            if (c==0) rfalse;
  580.            print "^There is a pile of building blocks here, ";
  581.            while (c>=0)
  582.            {   print_addr e.name;       ! Sneaky: print the "name" out
  583.                if (c>0) print " on ";   ! using its dictionary address
  584.                c--; e=parent(e);
  585.            }
  586.            ".";
  587.        ],
  588.        before
  589.        [ c;
  590.          PutOn:
  591.            if (second has is_cube)
  592.            {   if (child(second)~=0 && child(second) has is_cube)
  593.                    "There's no room on the top of one cube for two more, side \
  594.                     by side.";
  595.            }
  596.            else
  597.                print "(They're really intended \
  598.                       to be piled on top of each other.)^";
  599.            c=second; while (c has is_cube) c=parent(c);
  600.            if (c~=location or mantelpiece) "Too unsteady a base.";
  601.        ],
  602.        after
  603.        [ c stack;
  604.          PutOn:
  605.            stack=noun;
  606.            while (parent(stack) has is_cube) { stack=parent(stack); c++; }
  607.            if (c<2)
  608.            {   if (the_child has general) rtrue;
  609.                rfalse;
  610.            }
  611.            if (c==2) "The pile of three cubes is unsteady, but viable.";
  612.            if (the_child has general)
  613.            {   Achieved(3);
  614.                "^Expertly he keeps the pile of four cubes stable.";
  615.            }
  616.            stack=noun;
  617.            while (parent(stack) has is_cube)
  618.            {   c=stack; stack=parent(stack); move c to location; }
  619.            "The pile of four cubes wobbles, wobbles, steadies... and suddenly \
  620.             collapses!";
  621.          Take:
  622.            stack=child(noun); if (stack==0) rfalse;
  623.            while (stack~=0)
  624.            { c=stack; stack=child(stack); move c to location; }
  625.            "Your pile of cubes is collapsed as a result.";
  626.        ],
  627.   has  supporter is_cube;
  628.  
  629. Nearby cube1 "green cube"
  630.  class Cube_Class
  631.   with name "green";
  632. Nearby cube2 "red cube"
  633.  class Cube_Class
  634.   with name "red";
  635. Nearby cube3 "yellow cube"
  636.  class Cube_Class
  637.   with name "yellow";
  638. Nearby cube4 "blue cube"
  639.  class Cube_Class
  640.   with name "blue";
  641.  
  642. ! ----------------------------------------------------------------------------
  643. ! >CH  A guest appearance by my cousin Christopher, aged six, who plays with
  644. !      one thing at a time (but easily forgets which).  Being "transparent"
  645. !      (no reflection on him!) means the parser allows the player to examine
  646. !      whatever he's playing with... but not to take it from him.
  647. ! ----------------------------------------------------------------------------
  648.  
  649. Nearby the_child "Christopher"
  650.   with name "child" "boy" "chris" "christopher",
  651.        describe
  652.        [;  print "^A boy called Christopher sits here";
  653.            if (child(the_child)~=0)
  654.            {   print ", playing with "; InDefArt(child(the_child));
  655.            }
  656.            ".";
  657.        ],
  658.        life
  659.        [ x; Ask:
  660.              if (second=='juggling' or 'fluorescent' or 'ball')
  661.                  "~That's mine!~";
  662.              if (second=='helium' or 'balloon')
  663.                  "Christopher yawns.";
  664.              if (second=='cube' or 'cubes')
  665.                  "~Bet I can make a higher tower than you.~";
  666.              if (second=='toys' or 'toyshop')
  667.                  "~Isn't it fabulous here?~";
  668.              "~Dunno.~";
  669.           Answer:
  670.              if (special_word=='hello' or 'hallo' or 'hi')
  671.                  "~Hello,~ says Christopher cheerfully.";
  672.              "Christopher seems preoccupied.";
  673.           Attack: remove self;
  674.              "Christopher makes a run for it, effortlessly slipping past you!";
  675.           Kiss: "~That's soppy, that is.~";
  676.           Give:
  677.              if (noun==balloon) "He's too bored by the balloon.";
  678.              x=child(the_child);
  679.              if (x~=0)
  680.              {   move x to location;
  681.                  print "He forgets about "; DefArt(x); print " and ";
  682.              }
  683.              else print "He ";
  684.              print "eagerly grabs "; DefArt(noun); move noun to the_child; ".";
  685.           Order:
  686.              if (action==##Drop && noun==child(the_child))
  687.                  "~Won't!  It's mine!~";
  688.              if (action==##Take) "Christopher can't be bothered.";
  689.              if (action==##Give && second==player)
  690.                  "~Get your own!~";
  691.              if (action==##Go) "~I like it here!~";
  692.              if (action==##PutOn)
  693.              {   if (noun~=child(the_child)) "He is mightily confused.";
  694.                  if (noun hasnt is_cube || second hasnt is_cube)
  695.                      "He can't see the point of this.";
  696.                  print "Christopher leans over with great concentration \
  697.                      and does so.^";
  698.                  move noun to player; give self general;
  699.                  <PutOn noun second>;
  700.                  give self ~general; rtrue;
  701.              }
  702.        ],
  703.        each_turn
  704.        [ i;  if (random(3)~=1) rtrue;
  705.            print "^Christopher ";
  706.            i=random(4); if (i==1) "yawns."; if (i==2) "frowns.";
  707.            if (i==3) "stretches."; "hums tonelessly.";
  708.        ],
  709.   has  animate proper transparent;
  710.  
  711. Object ball "fluorescent juggling ball" the_child
  712.   with initial "On the floor is a fluorescent juggling ball!",
  713.        name "fluorescent" "juggling" "ball",
  714.        description "It glows with soft light."
  715.   has  light;
  716.  
  717. ! ----------------------------------------------------------------------------
  718. ! >OF  A simple movement rule.
  719. ! ----------------------------------------------------------------------------
  720.  
  721. Object Office "Office"
  722.   with description
  723.           "A small, grey office, with a broad stone mantelpiece.  \
  724.            In the east wall is a doorway marked ~Exit~, and the Toyshop, \
  725.            of course, lies north.",
  726.        cant_go "The Toyshop floor lies north.",
  727.        n_to West_End,
  728.        e_to
  729.        [; if (score~=MAX_SCORE)
  730.               print_ret "A gong sounds.  ~You cannot leave the Toyshop until \
  731.                   you have done 5 interesting things!~";
  732.           deadflag=2;
  733.           "A gong sounds.  ~Congratulations!  You may now leave the Toyshop \
  734.            and begin writing your own Inform game!~";
  735.        ],
  736.   has  light;
  737.  
  738. Nearby mantelpiece "mantelpiece"
  739.   with name "mantel" "mantle" "piece" "mantelpiece"
  740.   has  scenery supporter;
  741.  
  742. ! ----------------------------------------------------------------------------
  743. ! >TB  A somewhat acquisitive container... but it can be taught to behave.
  744. ! ----------------------------------------------------------------------------
  745.  
  746. Nearby toothed_bag "toothed bag"
  747.   with name "toothed" "bag",
  748.        initial "In one corner is a curious, toothed bag.",
  749.        description "A capacious bag with a toothed mouth.",
  750.        before
  751.        [; LetGo: "The bag defiantly bites itself \
  752.                   shut on your hand until you desist.";
  753.        ],
  754.        after
  755.        [; Receive:
  756.               if (noun==cone)
  757.               {   self.before=0; self.after=0;
  758.                   "The bag wriggles interminably as it tries \
  759.                    to eat the enormous mass of marzipan.  That'll \
  760.                    teach it.";
  761.               }
  762.               print "The bag wriggles hideously as it swallows ";
  763.               DefArt(inp1); ".";
  764.        ],
  765.   has  container open;
  766.  
  767. ! ----------------------------------------------------------------------------
  768. ! >SL  Which can be put on the mantelpiece: the first time this is done, the
  769. !      game randomly decides which end is higher, and sticks to this decision.
  770. ! ----------------------------------------------------------------------------
  771.  
  772. Object spirit_level "spirit level" toothed_bag
  773.   with name "spirit" "level" "wood" "flask",
  774.        number 0,
  775.        description "A length of wood containing a flask of viscous \
  776.            green liquid, in which a bubble is trapped.",
  777.        before
  778.        [; Examine:
  779.           if (parent(spirit_level)==mantelpiece)
  780.           {   print "The bubble is at the ";
  781.               if (self.number==1) "northeast end.";
  782.               "southeast end.";
  783.           } 
  784.        ],
  785.        after
  786.        [; PutOn: if (second~=mantelpiece) rfalse;
  787.            if (spirit_level hasnt general) self.number=random(2);
  788.            give spirit_level general; Achieved(4);
  789.            print "You put the spirit level on the mantelpiece, \
  790.                   and the bubble slowly drifts towards the ";
  791.            if (self.number==1) "northeast.";
  792.            "southwest.";
  793.        ];
  794.  
  795. Object key "iron key" mantelpiece
  796.   with name "iron" "key", article "an";
  797.  
  798. ! ----------------------------------------------------------------------------
  799. ! >BB  A blackboard which can be written on or wiped clear.
  800. ! ----------------------------------------------------------------------------
  801.  
  802. #IFDEF WITH_BOARD;
  803.  
  804. Object chalk "stick of chalk" mantelpiece
  805.   with name "stick" "of" "chalk";
  806.  
  807. Global boardtext string 64;
  808.  
  809. Object blackboard "blackboard" Office
  810.   with name "board" "blackboard" "black",
  811.        describe
  812.        [;  <<Examine self>>; ],
  813.        before
  814.        [ i f;
  815.            Examine:
  816.                for (i=1:i<=boardtext->0:i++)
  817.                    if (boardtext->i~=' ' or 0) f=1;
  818.                if (f==0)
  819.                {   print "^The office blackboard is wiped clean.^";
  820.                    if (self hasnt general)
  821.                    {   give self general;
  822.                        "^[To write on it, try   > write ~message...~]";
  823.                    }
  824.                    rtrue;
  825.                }
  826.                print "^The office blackboard bears the message:^    ";
  827.                for (i=1:i<=boardtext->0:i++)
  828.                {   f=boardtext->i;
  829.                    if (f~=0) print char f;
  830.                }
  831.                new_line; rtrue;
  832.            Rub: for (i=1:i<=boardtext->0:i++) boardtext->i = ' ';
  833.                   "You wipe the blackboard clean.";
  834.        ],
  835.   has  static;
  836.  
  837. Global from_char; Global to_char;
  838. [ QuotedText i j f;
  839.    i = parse->((++wn)*4-3);
  840.    if (buffer->i=='"')
  841.    {   for (j=i+1:j<=(buffer->1)+1:j++)
  842.            if (buffer->j=='"') f=j;
  843.        if (f==0) return -1;
  844.        from_char = i+1; to_char=f-1;
  845.        if (from_char>to_char) return -1;
  846.        while (f> (parse->(wn*4-3))) wn++; wn++;
  847.        return 1;
  848.    }
  849.    return -1;
  850. ];
  851.  
  852. [ WriteSub i j;
  853.    if (parent(chalk)~=player) "You're holding nothing to write with.";
  854.    if (location~=parent(blackboard)) "The blackboard is elsewhere.";
  855.    for (i=from_char,j=1:i<=to_char && j<boardtext->0:i++,j++)
  856.        boardtext->j = buffer->i;
  857.    for (:j<boardtext->0:j++) boardtext->j=0;
  858.    <<Examine blackboard>>;
  859. ];
  860. #ENDIF;
  861.  
  862. ! ----------------------------------------------------------------------------
  863. !   End of object definitions.
  864. ! ----------------------------------------------------------------------------
  865. !
  866. !   Routines and Entry Points
  867. !
  868. !   (Fuller examples can be found in the "Advent" source code.)
  869. !
  870. !   Initialise() just sets up the initial state of the game.
  871. !   We are required to set "location" to the start location of the
  872. !   player; the rest is optional.
  873. !
  874. !   StartDaemon(balloon)  starts the process which blows the balloon back
  875. !   and forth.
  876. ! ----------------------------------------------------------------------------
  877. Object chair "chair" Toyshop
  878.   with name "chair"
  879.   has  supporter enterable;
  880.  
  881. [ Initialise;
  882.   location=chair;  move satchel to player;
  883.  
  884.   print "^^^^^~What's so special about Inform 5,~ is the last thing you \
  885.          remember saying to the mad alchemist.  Big mistake...^^";
  886.  
  887.   StartDaemon(balloon);
  888. ];
  889.  
  890. ! ----------------------------------------------------------------------------
  891. !   Print names of tasks out (when the library asks us to).  Note that they
  892. !   are numbered from 0 to NUMBER_TASKS-1.
  893. ! ----------------------------------------------------------------------------
  894.  
  895. [ PrintTaskName ach;
  896.   if (ach==0) "eating a sweet";
  897.   if (ach==1) "driving the car";
  898.   if (ach==2) "shutting out the draught";
  899.   if (ach==3) "building a tower of four";
  900.   if (ach==4) "seeing which way the mantelpiece leans";
  901. ];
  902.  
  903. [ PrintRank;
  904.   print ", earning you the rank of ";
  905.  
  906.   if (score >= 5)  "Toyshop manager.";
  907.   if (score >= 4)  "undergraduate.";
  908.   if (score >= 3)  "schoolchild.";
  909.   if (score >= 2)  "nursery-school child.";
  910.   if (score >= 1)  "toddler.";
  911.   "newborn baby.";
  912. ];
  913.  
  914. [ HelpMenu;
  915.   if (menu_item==0)  { item_width=8; item_name="About Adventure";
  916.                        if (deadflag==2) return 4; else return 3;
  917.                      }
  918.   if (menu_item==1)  { item_width=6; item_name="Instructions"; }
  919.   if (menu_item==2)  { item_width=4; item_name="History";      }
  920.   if (menu_item==3)  { item_width=6; item_name="Authenticity"; }
  921.   if (menu_item==4)  { item_width=7; item_name="Did you know..."; }
  922. ];
  923.  
  924. [ GiveHint h k;
  925.   print_paddr h; new_line; new_line;
  926.   read_char 1 0 0 k;
  927.   if (k == 'H' or 'h') rfalse;
  928.   rtrue;
  929. ];
  930.  
  931. [ HelpInfo;
  932.  if (menu_item==1)
  933.  {      print "(Press ENTER to return to the main menu, or H for another hint.)^^";
  934.         if (GiveHint("(1/3)  The hints may not tell you all at once.")==1) rtrue;
  935.         if (GiveHint("(2/3)  But keep asking...")==1) rtrue;
  936.         "(3/3)  ...and the truth is revealed.";
  937.  }
  938.  if (menu_item==2)
  939.  {   
  940.  DoMenu("There is information provided on the following:^\
  941.          ^     Balls\
  942.          ^     Drivel\
  943.          ^     Goalposts",
  944.          #r$HelpMenu, #r$HelpInfo2); return 2;
  945.  }
  946.  
  947.  if (menu_item==3)
  948.  {
  949.  }
  950.  
  951. ];
  952.  
  953. [ HelpInfo2;
  954.  if (menu_item==1) "Different!";
  955.  "J. S. Bach.";
  956. ];
  957.  
  958.  
  959. [ HelpSub;
  960.  
  961.  if (deadflag~=2)
  962.  DoMenu("There is information provided on the following:^\
  963.          ^     Instructions for playing\
  964.          ^     The history of this game\
  965.          ^     How authentic is this edition?^",
  966.          #r$HelpMenu, #r$HelpInfo);
  967.  else
  968.  DoMenu("There is information provided on the following:^\
  969.          ^     Instructions for playing\
  970.          ^     The history of this game\
  971.          ^     How authentic is this edition?\
  972.          ^     Did you know...^",
  973.          #r$HelpMenu, #r$HelpInfo);
  974.  
  975. ];
  976.  
  977. ! ----------------------------------------------------------------------------
  978. !   Now (as promised earlier) we provide the replacement for BurnSub,
  979. !   specially adapted to the rules of the Toyshop:
  980. ! ----------------------------------------------------------------------------
  981.  
  982. [ BurnSub;
  983.     if (match hasnt light) "You have no source of flame.";
  984.     if (noun has animate) <<Attack noun>>;
  985.     if (noun==padded_floor)
  986.     {   deadflag=1;
  987.         "A gong sounds, but before a sepulchral voice finishes clearing \
  988.          its throat, the whole padded floor goes up in an inferno.";
  989.     }
  990.     "A gong sounds, and a sepulchral, rather disappointed voice says: \
  991.      ~It is forbidden to play with fire in the Toyshop.~";
  992. ];
  993.  
  994. ! ----------------------------------------------------------------------------
  995. !   And we provide one new action, "Burst", which in fact just passes over to
  996. !   "Attack", plus one for writing on the board:
  997. ! ----------------------------------------------------------------------------
  998.  
  999. [ BurstSub; <<Attack noun>>; ];
  1000.  
  1001. Include "Grammar";
  1002.  
  1003. Verb "burst" "pop" "prick" "stab" "pierce"
  1004.                 * noun                           -> Burst;
  1005.  
  1006. #IFDEF WITH_BOARD;
  1007. Verb "write"    * QuotedText -> Write;
  1008. #ENDIF;
  1009. Verb "help" * -> Help;
  1010.  
  1011. ! ----------------------------------------------------------------------------
  1012.